﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using SuperSocket.SocketBase;
using SuperSocket.SocketBase.Config;
using SuperSocket.SocketBase.Protocol;

namespace AccelerateSensor.SuperSocket.Server
{
    public class MyServer : AppServer<MySession, MyRequestInfo>
    {
        private readonly Dictionary<string, MySession> _sessionDic;

        private int _timeCount;

        public MyServer()
            : base(new DefaultReceiveFilterFactory<MyReceiveFilter, MyRequestInfo>())
        {
            _sessionDic = new Dictionary<string, MySession>();
        }

        protected override bool Setup(IRootConfig rootConfig, IServerConfig config)
        {
            Console.WriteLine("SmartVenue.Server Setup");
            Console.WriteLine($"SmartVenue.Server Listening on port: {config.Port}");
            return base.Setup(rootConfig, config);
        }

        protected override void OnStarted()
        {
            Console.WriteLine("SmartVenue.Server OnStarted");
            StartStatistic();
            base.OnStarted();
        }

        protected override void OnStopped()
        {
            Console.WriteLine();
            Console.WriteLine("SmartVenue.Server OnStopped");
            base.OnStopped();
        }

        private void StartStatistic()
        {
            ThreadPool.QueueUserWorkItem((state) =>
            {
                while (State == ServerState.Running)
                {
                    Thread.Sleep(10000);
                    Interlocked.Increment(ref _timeCount);

                    var sessionIdList = new List<string>();
                    lock (_sessionDic)
                    {
                        var sessionCount = _sessionDic.Count;
                        var packageCount = _sessionDic.Values.Select(t => t.PackageCount).Sum();

                        Console.WriteLine(
                            $"{DateTime.Now:T} sessionCount: {sessionCount}, pkg/s: {packageCount / _timeCount / 10}.");

                        //检测心跳
                        sessionIdList.Clear();
                        foreach (var session in _sessionDic.Values)
                        {
                            //if (session.Timeout)
                            //{
                            //    session.Close();
                            //    sessionIdList.Add(session.Id);
                            //    LogHelper.AddLog($"Close {session.Id} due to timeout.");
                            //}

                            session.ResetPackageCount();
                        }
                    }

                    foreach (var sessionId in sessionIdList)
                    {
                        UnRegisterSession(sessionId);
                    }
                }
            }, null);
        }

        public void RegisterSession(MySession session)
        {
            if (string.IsNullOrWhiteSpace(session.Id))
            {
                return;
            }

            lock (_sessionDic)
            {
                if (_sessionDic.ContainsKey(session.Id))
                {
                    _sessionDic[session.Id].Close(CloseReason.InternalError);
                    _sessionDic[session.Id] = session;
                }
                else
                {
                    _sessionDic.Add(session.Id, session);

                    if (_sessionDic.Count % 1000 == 0)
                    {
                        Console.WriteLine($"Session Count: {_sessionDic.Count}");
                    }
                }
            }
        }

        public void UnRegisterSession(string sessionId)
        {
            if (string.IsNullOrWhiteSpace(sessionId))
            {
                return;
            }

            lock (_sessionDic)
            {
                if (_sessionDic.ContainsKey(sessionId))
                {
                    _sessionDic.Remove(sessionId);
                }
            }
        }

        private bool IsSessionExist(string sessionId)
        {
            if (string.IsNullOrWhiteSpace(sessionId))
            {
                return false;
            }

            bool ret;
            lock (_sessionDic)
            {
                ret = _sessionDic.ContainsKey(sessionId);
            }

            return ret;
        }
    }
}
